AWS Step Functionsで起動ソースのEventBridge Ruleに応じて処理を分岐させる(AWS CDK v2)
こんにちは、CX事業本部 IoT事業部の若槻です。
最近の業務で、実行された時間によって処理を分岐させるAWS Step FunctionsのState Machineを作りたいことがありました。
そのState MachineはEventBridge RuleのCronスケジュールを起動ソースとしていたため、分岐させたい時間毎にRuleを分けて、起動ソースのRuleに応じてState Machine内で分岐がさせられないか?と考えました。
そこで今回は、AWS Step Functionsで起動ソースのEventBridge Ruleに応じて処理を分岐させる実装をAWS CDK v2で作ってみました。
やってみた
実装
AWS CDK v2(TypeScript)で次のようなCDKスタックを作成します。
import { Construct } from 'constructs'; import { aws_events, aws_events_targets, aws_stepfunctions, Stack, StackProps, } from 'aws-cdk-lib'; export class AwsAppStack extends Stack { constructor(scope: Construct, id: string, props: StackProps) { super(scope, id, props); const RULE_1_NAME = 'rule1'; // StateMachineの起動ソースに応じて分岐するChoice const choice = new aws_stepfunctions.Choice(this, 'choice'); choice.when( aws_stepfunctions.Condition.stringEquals( aws_stepfunctions.JsonPath.stringAt('$.resources[0]'), `arn:aws:events:${this.region}:${this.account}:rule/${RULE_1_NAME}`, ), new aws_stepfunctions.Pass(this, 'rule1Pass'), ); choice.otherwise(new aws_stepfunctions.Pass(this, 'otherPass')); // StateMachine const stateMachine = new aws_stepfunctions.StateMachine( this, 'stateMachine', { stateMachineName: 'stateMachine', definition: choice, }, ); // EventBridge Rule1(毎時0〜20分に起動) new aws_events.Rule(this, 'rule1', { ruleName: RULE_1_NAME, schedule: aws_events.Schedule.cron({ minute: '0-20', }), targets: [new aws_events_targets.SfnStateMachine(stateMachine)], }); // EventBridge Rule2(毎時21〜40分に起動) new aws_events.Rule(this, 'rule2', { ruleName: 'rule2', schedule: aws_events.Schedule.cron({ minute: '21-40', }), targets: [new aws_events_targets.SfnStateMachine(stateMachine)], }); } }
ここで、EventBridge Ruleにより起動された際のExecutionのInputは次のようになります。このうちresources
に起動元のRuleの情報が格納されているので、この値をStateMachine内の分岐処理で参照すれば良さそうです。
{ "version": "0", "id": "f5bb14f2-6316-d9ad-cae3-e03ea6c3a797", "detail-type": "Scheduled Event", "source": "aws.events", "account": "XXXXXXXXXXXX", "time": "2022-07-13T12:19:00Z", "region": "ap-northeast-1", "resources": [ "arn:aws:events:ap-northeast-1:XXXXXXXXXXXX:rule/rule1" ], "detail": {} }
そこでChoice Stateで、JsonPath.stringAt('$.resources[0]')
により取得したRuleが指定値(rule1
)と一致しているかどうかを判定しています。
上記をCDK Deployしてスタックをデプロイします。すると次のようなDefinitionのState Machineが作成されます。
{ "StartAt": "choice", "States": { "choice": { "Type": "Choice", "Choices": [ { "Variable": "$.resources[0]", "StringEquals": "arn:aws:events:ap-northeast-1:XXXXXXXXXXXX:rule/rule1", "Next": "rule1Pass" } ], "Default": "otherPass" }, "otherPass": { "Type": "Pass", "End": true }, "rule1Pass": { "Type": "Pass", "End": true } } }
動作確認
State Machineの実行一覧を見ると、EventBridge Ruleにより1分毎にState Machineが起動されています。
起動ソースがrule1
となる時間帯の実行を見ると、分岐がrule1Pass
に進んでいます。
起動ソースがrule2
となる時間帯の実行を見ると、分岐がotherPass
に進んでいます。
想定通りの動きとなっていますね!
(別解)起動ソースの情報を使わずに現在時間による分岐をしたい場合
ここまでは起動ソースのEventBridge Ruleが時間帯によって異なることを利用して分岐をさせましたが、起動ソースの情報を使わない(使えない)場合はどうすれば良いでしょう。
その場合は、EvaluateExpression Taskを次のように使用すれば、時間による判定処理を比較的簡単に実装できます。
const isAfter24HourJst = new aws_stepfunctions_tasks.EvaluateExpression( this, 'isAfter24HourJst', { expression: 'new Date().getHours() === 15', resultPath: '$.isAfter24HourJstOutPut', }, );
EvaluateExpressionはLambda関数が隠蔽されたTaskなので柔軟な判定処理が可能ですが、コストや実行速度の面で前述の起動ソース(およびJsonPath)を使用した方法には劣ります。メリット/デメリットを理解して適した方法を採用したいですね。
以上